package com.xxg.renrenproduct.service;

import com.alibaba.fastjson.JSON;
import com.xxg.renrencommon.api.SearchManager;
import com.xxg.renrencommon.domain.bean.CarryProductInfo;
import com.xxg.renrencommon.domain.bean.CarryProductSettingInfo;
import com.xxg.renrencommon.domain.bean.Product;
import com.xxg.renrencommon.domain.dao.RenrenShopGoods;
import com.xxg.renrencommon.domain.filedenum.RedisKeyEnum;
import com.xxg.renrencommon.domain.filedenum.productenum.CarryProductStatusEnum;
import com.xxg.renrencommon.domain.result.BaseResult;
import com.xxg.renrencommon.exception.ProductManagerException;
import com.xxg.renrencommon.exception.exceptionenum.ProductExceptionCodeCodeEnum;
import com.xxg.renrenproduct.component.ProductComponent;
import com.xxg.renrenproduct.dao.*;
import com.xxg.renrenproduct.domain.query.CarryProductQuery;
import com.xxg.renrenproduct.domain.query.DeleteCarryQuery;
import com.xxg.renrenproduct.domain.query.ListShopByStatusQuery;
import com.xxg.renrenproduct.domain.query.VerifyQuery;
import com.xxg.renrenproduct.domain.result.CarryProductResult;
import com.xxg.renrenproduct.domain.result.ListCarryProductResult;
import com.xxg.renrenproduct.domain.result.ShopInfoResult;
import com.xxg.renrenproduct.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * 类说明
 *
 * @author szj
 * @date 2021/11/30
 */
@Service
@Slf4j
public class CarryProductServiceImpl implements CarryProductService{
    @Resource
    private CarryProductInfoDao carryProductInfoDao;
    @Resource
    private CarryProductSettingInfoDao carryProductSettingInfoDao;
    @Resource
    private RenrenShopShopDao renrenShopShopDao;
    @Resource
    private RenrenShopGoodsDao renrenShopGoodsDao;
    @Resource
    private ProductComponent productComponent;
    @Resource
    private RedisUtil redisUtil;
    @DubboReference(version = "1.0.0")
    private SearchManager searchManager;
    private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), (r) -> {
        Thread thread = new Thread(r);
        thread.setName("CarryProduct_");
        return thread;
    }, new ThreadPoolExecutor.CallerRunsPolicy());
    private static final ReentrantLock LOCK = new ReentrantLock();

    @Override
    public BaseResult<Void> carry(String userId, CarryProductQuery query) {
        EXECUTOR.execute(() -> {
            Integer userIdInt = Integer.parseInt(userId);
            Integer spuId = query.getSpuId();
            // 找到最开始的spuId
            CarryProductInfo carryProductInfo1 = carryProductInfoDao.findByCarrySpuId(spuId);
            if (carryProductInfo1 != null) {
                spuId = carryProductInfo1.getSpuId();
            }
            Integer shopId = renrenShopShopDao.selectNormalShopIdByUserId(userIdInt);
            // 判断该商品是否属于自己
            long count = renrenShopGoodsDao.countByIdAndShopId(spuId, shopId);
            if (count > 0) {
                log.info("carry:{}", ProductExceptionCodeCodeEnum.CAN_NOT_CARRY_SELF.getName());
                return;
            }
            if (shopId == null) {
                log.info("carry:{}", ProductExceptionCodeCodeEnum.NO_SHOP_UNDER_USER.getName());
                return;
            }
            CarryProductInfo carryProductInfo = carryProductInfoDao.findByShopIdAndSpuId(shopId, spuId);
            if (carryProductInfo != null) {
                log.info("carry:{}", ProductExceptionCodeCodeEnum.HAS_CARRY.getName());
                return;
            }
            // 查询商品拥有者的userId
            Integer originShopId = renrenShopGoodsDao.selectShopIdByPrimaryKey(spuId);
            Integer originUserId = renrenShopShopDao.selectUserIdByPrimaryKey(originShopId);
            // 带货系数检查
            try {
                checkCarryRatio(query.getCarryRatio(), spuId, originUserId);
            } catch (ProductManagerException e) {
                log.error("carry_" + e.getMessage(), e);
                return;
            }
            // 带货状态判断，不需要申请就直接生成带货商品数据
            Integer status = null;
            try {
                status = judgeCarryProductStatus(spuId, originUserId);
            } catch (ProductManagerException e) {
                log.error("carry_" + e.getMessage(), e);
                return;
            }
            carryProductInfo = new CarryProductInfo();
            carryProductInfo.setSpuId(spuId);
            carryProductInfo.setOriginUserId(originUserId);
            carryProductInfo.setOriginShopId(originShopId);
            carryProductInfo.setUserId(userIdInt);
            carryProductInfo.setShopId(shopId);
            carryProductInfo.setCarryRatio(query.getCarryRatio());
            carryProductInfo.setStatus(status);
            carryProductInfo.setCategoryIds(query.getCategoryIds());
            if (CarryProductStatusEnum.NORMAL.match(status)) {
                try {
                    carryProductInfo = productComponent.copyGoodsToCurrentUserShop(userIdInt, shopId, spuId, query.getCategoryIds(), query.getCarryRatio(), carryProductInfo);
                } catch (Exception e) {
                    log.error("carry_" + ProductExceptionCodeCodeEnum.GATHER_FAIL.getName() + "_" + e.getMessage(), e);
                    return;
                }
            }
            log.info("ready insert carryProductInfo:{}", JSON.toJSONString(carryProductInfo));
            carryProductInfoDao.insert(carryProductInfo);
        });
        return new BaseResult<>();
    }

    @Override
    public BaseResult<List<ShopInfoResult>> listShopReceiveByStatus(String userId, ListShopByStatusQuery query) {
        // 查出店铺信息
        List<ShopInfoResult> shopInfoResults = carryProductInfoDao.findByOriginUserIdAndStatus(Integer.parseInt(userId), query.getStatus(), query.getPageNo(), query.getPageSize());
        if (replenishShopInfo(shopInfoResults, Integer.parseInt(userId), query.getStatus(), true)) {return new BaseResult<>(new ArrayList<>());}
        return new BaseResult<>(shopInfoResults);
    }

    private boolean replenishShopInfo(List<ShopInfoResult> shopInfoResults, Integer userId, List<Integer> status, boolean isFindReceive) {
        if (shopInfoResults == null || shopInfoResults.size() == 0) {
            return true;
        }
        List<Integer> collect = shopInfoResults.stream().map(ShopInfoResult::getId).collect(Collectors.toList());
        // 查询店铺详细信息
        List<RenrenShopShop> renrenShopShops = renrenShopShopDao.selectByIds(collect);
        if (renrenShopShops == null) {
            log.info("replenishShopInfo_shopIds:{}", collect);
            return true;
        }
        Map<Integer, RenrenShopShop> shopMap = renrenShopShops.stream().collect(Collectors.toMap(RenrenShopShop::getId, renrenShopShop -> renrenShopShop));
        // 组合数据
        shopInfoResults.forEach(shopInfoResult -> {
            // 查已审核信息
            if (status.size() > 1) {
                List<CarryProductInfo> carryProductInfos;
                if (isFindReceive) {
                    carryProductInfos = carryProductInfoDao.findByOriginUserIdAndStatusAndShopId(userId, status, shopInfoResult.getId());
                }else {
                    carryProductInfos = carryProductInfoDao.findByUserIdAndStatusAndOriginShopId(userId, status, shopInfoResult.getId());
                }
                boolean hasPass = false;
                boolean hasReject = false;
                for (CarryProductInfo carryProductInfo : carryProductInfos) {
                    if (CarryProductStatusEnum.VERIFY_PASS.match(carryProductInfo.getStatus())) {
                        hasPass = true;
                    }
                    if (CarryProductStatusEnum.VERIFY_REJECT.match(carryProductInfo.getStatus())) {
                        hasReject = true;
                    }
                    if (hasPass && hasReject) {
                        break;
                    }
                }
                if (!hasPass) {
                    shopInfoResult.setVerifyStatus(3);
                }else if (!hasReject) {
                    shopInfoResult.setVerifyStatus(1);
                }else {
                    shopInfoResult.setVerifyStatus(2);
                }
            }
            shopInfoResult.setName(shopMap.get(shopInfoResult.getId()).getName());
            shopInfoResult.setLogo(shopMap.get(shopInfoResult.getId()).getLogo());
        });
        return false;
    }

    @Override
    public BaseResult<List<ShopInfoResult>> listShopSendByStatus(String userId, ListShopByStatusQuery query) {
        // 查出店铺信息
        List<ShopInfoResult> shopInfoResults = carryProductInfoDao.findByUserIdAndStatus(Integer.parseInt(userId), query.getStatus(), query.getPageNo(), query.getPageSize());
        if (replenishShopInfo(shopInfoResults, Integer.parseInt(userId), query.getStatus(), false)) {return new BaseResult<>(new ArrayList<>());}
        return new BaseResult<>(shopInfoResults);
    }

    @Override
    public BaseResult<ListCarryProductResult> listReceiveByStatus(String userId, ListShopByStatusQuery query) {
        List<CarryProductInfo> carryProductInfoList = carryProductInfoDao.findPageByOriginUserIdAndStatusAndShopId(Integer.parseInt(userId), query.getStatus(), query.getShopId(), query.getPageNo(), query.getPageSize());
        if (carryProductInfoList == null || carryProductInfoList.size() == 0) {
            return new BaseResult<>();
        }
        ListCarryProductResult listCarryProductResult = getListCarryProductResult(query, carryProductInfoList);

        return new BaseResult<>(listCarryProductResult);
    }

    private ListCarryProductResult getListCarryProductResult(ListShopByStatusQuery query, List<CarryProductInfo> carryProductInfoList) {
        RenrenShopShop renrenShopShop = renrenShopShopDao.selectByPrimaryKey(query.getShopId());
        ShopInfoResult shopInfoResult = new ShopInfoResult();
        shopInfoResult.setId(renrenShopShop.getId());
        shopInfoResult.setUserId(renrenShopShop.getUserId());
        shopInfoResult.setName(renrenShopShop.getName());
        shopInfoResult.setLogo(renrenShopShop.getLogo());
        shopInfoResult.setLatestTime(carryProductInfoList.get(0).getCreateTime());

        carryProductInfoList = carryProductInfoList.stream().skip((query.getPageNo() - 1) * query.getPageSize()).limit(query.getPageSize()).collect(Collectors.toList());
        List<Integer> collect = carryProductInfoList.stream().map(CarryProductInfo::getSpuId).collect(Collectors.toList());
        String oneSkuUnderSpuBySpuId = searchManager.listProductOneSkuUnderSpuBySpuId(collect);
        List<Product> products = JSON.parseArray(oneSkuUnderSpuBySpuId, Product.class);
        Map<Integer, Product> productMap = products.stream().collect(Collectors.toMap(Product::getSpuId, product -> product));
        List<CarryProductResult> carryProductResults = new ArrayList<>(carryProductInfoList.size());
        carryProductInfoList.forEach(carryProductInfo -> {
            CarryProductResult carryProductResult = new CarryProductResult();
            carryProductResult.setId(carryProductInfo.getId());
            carryProductResult.setStatus(carryProductInfo.getStatus());
            carryProductResult.setProduct(productMap.get(carryProductInfo.getSpuId()));
            carryProductResults.add(carryProductResult);
        });

        ListCarryProductResult listCarryProductResult = new ListCarryProductResult();
        listCarryProductResult.setShopInfoResult(shopInfoResult);
        listCarryProductResult.setCarryProductResults(carryProductResults);
        return listCarryProductResult;
    }

    @Override
    public BaseResult<ListCarryProductResult> listSendByStatus(String userId, ListShopByStatusQuery query) {
        List<CarryProductInfo> carryProductInfoList = carryProductInfoDao.findPageByUserIdAndStatusAndOriginShopId(Integer.parseInt(userId), query.getStatus(), query.getShopId(), query.getPageNo(), query.getPageSize());
        if (carryProductInfoList == null || carryProductInfoList.size() == 0) {
            return new BaseResult<>();
        }
        return new BaseResult<>(getListCarryProductResult(query, carryProductInfoList));
    }

    @Override
    public BaseResult<Void> verify(String userId, VerifyQuery query) {
        final int userIdInt = Integer.parseInt(userId);
        if (query.getId() == null) {
            // 全部同意或拒绝
            if (CarryProductStatusEnum.VERIFY_PASS.match(query.getStatus())) {
                ArrayList<Integer> status = new ArrayList<>();
                status.add(CarryProductStatusEnum.READY_VERIFY.getValue());
                // 审核通过，需要复制商品到对应店铺
                List<CarryProductInfo> carryProductInfos = carryProductInfoDao.findByOriginUserIdAndStatusAndShopId(userIdInt, status, query.getShopId());
                if (carryProductInfos != null && carryProductInfos.size() > 0) {
                    Boolean absent = redisUtil.setIfAbsent(String.format(RedisKeyEnum.CARRY_PRODUCT_VERIFY.key(), userId, query.getShopId()),
                            carryProductInfos.size(), RedisKeyEnum.CARRY_PRODUCT_VERIFY.time());
                    if (absent) {
                        return new BaseResult<>(ProductExceptionCodeCodeEnum.CARRYING);
                    }
                    carryProductInfos.forEach(carryProductInfo -> EXECUTOR.execute(() -> {
                        CarryProductInfo carryProductInfo1;
                        try {
                            carryProductInfo1 = productComponent.copyGoodsToCurrentUserShop(userIdInt, carryProductInfo.getShopId(), carryProductInfo.getSpuId(), carryProductInfo.getCategoryIds(), carryProductInfo.getCarryRatio(), carryProductInfo);
                        } catch (Exception e) {
                            log.error("carry_" + ProductExceptionCodeCodeEnum.CARRY_FAIL.getName() + "_" + e.getMessage(), e);
                            return;
                        }finally {
                            LOCK.lock();
                            try {
                                Object o = redisUtil.get(String.format(RedisKeyEnum.CARRY_PRODUCT_VERIFY.key(), userId, query.getShopId()));
                                int i = (int) o;
                                if (--i <= 0) {
                                    redisUtil.del(String.format(RedisKeyEnum.CARRY_PRODUCT_VERIFY.key(), userId, query.getShopId()));
                                }else {
                                    redisUtil.set(String.format(RedisKeyEnum.CARRY_PRODUCT_VERIFY.key(), userId, query.getShopId()),
                                            carryProductInfos.size(), RedisKeyEnum.CARRY_PRODUCT_VERIFY.time());
                                }
                            } finally {
                                LOCK.unlock();
                            }
                        }
                        log.info("ready update carryProductInfo:{}", JSON.toJSONString(carryProductInfo1));
                        carryProductInfoDao.updateStatusById(carryProductInfo.getId(), query.getShopId(), query.getStatus(), carryProductInfo1.getCarrySpuId());

                    }));
                }
            }else {
                carryProductInfoDao.updateStatusByShopIdAndUserId(userIdInt, query.getShopId(), query.getStatus());
            }
        }else {
            // 单个同意或拒绝
            CarryProductInfo carryProductInfo1 = null;
            if (CarryProductStatusEnum.VERIFY_PASS.match(query.getStatus())) {
                // 审核通过，需要复制商品到对应店铺
                CarryProductInfo carryProductInfo = carryProductInfoDao.findById(query.getId());
                try {
                    carryProductInfo1 = productComponent.copyGoodsToCurrentUserShop(userIdInt, carryProductInfo.getShopId(), carryProductInfo.getSpuId(), carryProductInfo.getCategoryIds(), carryProductInfo.getCarryRatio(), carryProductInfo);
                } catch (Exception e) {
                    log.error("carry_" + ProductExceptionCodeCodeEnum.CARRY_FAIL.getName() + "_" + e.getMessage(), e);
                    return new BaseResult<>(ProductExceptionCodeCodeEnum.CARRY_FAIL);
                }

            }
            log.info("ready update carryProductInfo:{}", JSON.toJSONString(carryProductInfo1));
            carryProductInfoDao.updateStatusById(query.getId(), query.getShopId(), query.getStatus(), carryProductInfo1 == null ? null : carryProductInfo1.getCarrySpuId());
        }
        return new BaseResult<>();
    }

    @Override
    public BaseResult<Void> deleteCarry(String userId, DeleteCarryQuery query) {
        int userIdInt = Integer.parseInt(userId);
        CarryProductInfo carryProductInfo = carryProductInfoDao.findById(query.getId());
        if (carryProductInfo == null) {
            return new BaseResult<>();
        }
        if (!carryProductInfo.getUserId().equals(userIdInt)) {
            return new BaseResult<>();
        }
        if (CarryProductStatusEnum.NORMAL.match(carryProductInfo.getStatus()) || CarryProductStatusEnum.VERIFY_PASS.match(carryProductInfo.getStatus())) {
            // 生成商品的需要删除对应表里的数据
            try {
                productComponent.deleteGoodsByGoodsId(carryProductInfo);
            } catch (Exception e) {
                log.error("deleteCarry_" + e.getMessage(), e);
                return new BaseResult<>(ProductExceptionCodeCodeEnum.DELETE_CARRY_FAIL);
            }
        }
        carryProductInfoDao.removeById(query.getId());
        return new BaseResult<>();
    }

    private Integer judgeCarryProductStatus(Integer spuId, Integer userId) throws ProductManagerException{
        int status = CarryProductStatusEnum.NORMAL.getValue();
        // 查询spu对应设置，没有则使用全局设置
        CarryProductSettingInfo byUserIdAndSpuId = carryProductSettingInfoDao.findByUserIdAndSpuId(userId, spuId);
        if (byUserIdAndSpuId == null) {
            CarryProductSettingInfo globalByUserId = carryProductSettingInfoDao.findGlobalByUserId(userId);
            if (globalByUserId != null) {
                if (globalByUserId.getCarryAble()) {
                    status = globalByUserId.getCarryApplyAble() ? CarryProductStatusEnum.READY_VERIFY.getValue() : CarryProductStatusEnum.NORMAL.getValue();
                }else {
                    throw new ProductManagerException(ProductExceptionCodeCodeEnum.CARRY_ILLEGAL);
                }
            }
        }else {
            if (byUserIdAndSpuId.getCarryAble()) {
                status = byUserIdAndSpuId.getCarryApplyAble() ? CarryProductStatusEnum.READY_VERIFY.getValue() : CarryProductStatusEnum.NORMAL.getValue();
            }else {
                throw new ProductManagerException(ProductExceptionCodeCodeEnum.CARRY_ILLEGAL);
            }

        }
        return status;
    }

    private void checkCarryRatio(Double carryRatio, Integer spuId, Integer userId) throws ProductManagerException{
        Double defaultMinRatio = 0D;
        Double defaultMaxRatio = 2D;
        // 查询spu对应系数，没有则使用全局系数
        CarryProductSettingInfo byUserIdAndSpuId = carryProductSettingInfoDao.findByUserIdAndSpuId(userId, spuId);
        if (byUserIdAndSpuId == null) {
            CarryProductSettingInfo globalByUserId = carryProductSettingInfoDao.findGlobalByUserId(userId);
            if (globalByUserId != null) {
                defaultMinRatio = globalByUserId.getMinCarryRatio();
                defaultMaxRatio = globalByUserId.getMaxCarryRatio();
            }
        }else {
            defaultMinRatio = byUserIdAndSpuId.getMinCarryRatio();
            defaultMaxRatio = byUserIdAndSpuId.getMaxCarryRatio();
        }
        if (carryRatio < defaultMinRatio || carryRatio > defaultMaxRatio) {
            throw new ProductManagerException(ProductExceptionCodeCodeEnum.CARRY_RATIO_ILLEGAL);
        }
    }
}
